package main.java.DMDE.view;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import main.java.DMDE.controllers.IAttributeController;
import main.java.DMDE.infrastructure.visual.AttributeTreeNode;
import main.java.DMDE.infrastructure.visual.OperationNode;
import main.java.DMDE.model.Attribute;
import main.java.DMDE.model.Modifier;
import main.java.DMDE.model.Type;
import main.java.DMDE.model.Visibility;

public class AttributeView extends CommonView implements IAttributeView {

    private IAttributeController attribController;

    private JTree attributes;
    private DefaultTreeModel attributeModel;
    private List<Attribute> attributeList;
    private Attribute attributeSelected;

    public AttributeView() {
	super();
	attributeList = new ArrayList<Attribute>();
    }

    @Override
    public JPanel getPanel() {
	return panel;
    }

    @Override
    protected void initList() {
	this.attributes = new JTree();
	scrollPane.setViewportView(attributes);
	attributeModel = new DefaultTreeModel(new DefaultMutableTreeNode("Attributes"));
	attributes.setModel(attributeModel);
	this.attributeSelected = null;
	attributes.addTreeSelectionListener(new TreeSelectionListener() {
	    @Override
	    public void valueChanged(TreeSelectionEvent e) {
		if (attributes.getLastSelectedPathComponent() instanceof AttributeTreeNode) {
		    Attribute attribute = ((AttributeTreeNode) attributes
			    .getLastSelectedPathComponent()).getAttribute();
		    attributeSelected(attribute);
		} else {
		    attributeSelected = null;
		}
	    }

	});

	attributes.addKeyListener(new KeyListener() {
	    @Override
	    public void keyTyped(KeyEvent e) {
	    }

	    @Override
	    public void keyPressed(KeyEvent e) {
		if (e.getKeyCode() == KeyEvent.VK_DELETE) {
		    if (attributes.getLastSelectedPathComponent() instanceof AttributeTreeNode) {
			AttributeTreeNode attributeTreeNode = (AttributeTreeNode) attributes
				.getLastSelectedPathComponent();
			Object parent = ((MutableTreeNode) attributes
				.getLastSelectedPathComponent()).getParent();
			if (parent instanceof AttributeTreeNode) {
			    // ((AttributeTreeNode) parent)
			    // .removeOwnAttribute(attributeTreeNode
			    // .getAttribute());
			} else {
			    // controller.removeAttribute(attributeTreeNode
			    // .getAttribute());
			}
			attributeModel.removeNodeFromParent(
				(MutableTreeNode) attributes.getLastSelectedPathComponent());
			cleanView();
		    }
		}
	    }

	    @Override
	    public void keyReleased(KeyEvent e) {
	    }
	});
    }

    private void attributeSelected(Attribute attribute) {
	if (attribute != null) {
	    this.attributeSelected = attribute;
	    this.name.setText(attributeSelected.getName());
	    this.type.setText(attributeSelected.getType().getName());
	    Visibility visibility = attributeSelected.getVisibility();
	    if (visibility.equals(Visibility.PRIVATE))
		btnPrivate.doClick();
	    else {
		if (visibility.equals(Visibility.PROTECTED))
		    btnProtected.doClick();
		else
		    btnPublic.doClick();
	    }
	    List<Modifier> modifiers = attribute.getModifiers();
	    for (Modifier modif : modifiers) {
		if (modif.equals(Modifier.STATIC))
		    staticCheckBox.doClick();
		else
		    finalCheckBox.doClick();

	    }
	}
    }

    @Override
    public void setController(IAttributeController attributeController) {
	this.attribController = attributeController;
    }

    @Override
    protected void create() {
	if (this.name.getText().equals("")) {
	    this.showNameError();
	} else {
	    Attribute attributeCreated = this.attribController.addAttribute();
	    if (attributeCreated != null) {
		((DefaultMutableTreeNode) attributeModel.getRoot())
			.add(new AttributeTreeNode(attributeCreated));
		cleanView();
	    }
	}
    }

    @Override
    protected void cleanTree() {
	attributes.revalidate();
	attributes.repaint();
	attributes.updateUI();
	attributes.clearSelection();
    }

    private void showNameError() {
	JOptionPane.showMessageDialog(null, "Attributes should have a name");
    }

    @Override
    public String getName() {
	return this.name.getText();
    }

    @Override
    public Type getType() {
	return new Type(this.type.getText());
    }

    @Override
    public Visibility getVisibility() {
	if (btnPrivate.isSelected())
	    return Visibility.PRIVATE;
	else {
	    if (btnProtected.isSelected())
		return Visibility.PROTECTED;
	    else
		return Visibility.PUBLIC;
	}
    }

    @Override
    public List<Modifier> getModifiers() {
	List<Modifier> modifiers = new ArrayList<Modifier>();
	if (finalCheckBox.isSelected())
	    modifiers.add(Modifier.FINAL);
	if (staticCheckBox.isSelected())
	    modifiers.add(Modifier.STATIC);
	return modifiers;
    }

    @Override
    protected void edit() {
	if (attributeSelected != null) {
	    if (this.attribController.editAttribute(attributeSelected)) {
		attributeSelected = null;
		cleanView();
	    } else
		showNameError();
	}
    }

    @Override
    protected void remove() {
	AttributeTreeNode node = (AttributeTreeNode) attributes.getLastSelectedPathComponent();
	if (node != null) {
	    if (this.attribController.removeAttribute(node.getAttribute())) {
		attributeModel.removeNodeFromParent(node);
		attributeSelected = null;
		cleanView();
	    }
	}
    }

    @Override
    public List<Attribute> getAttributes() {
	loadAttributes();
	return attributeList;
    }

    @Override
    public void loadAttributes() {
	DefaultMutableTreeNode root = (DefaultMutableTreeNode) attributes.getModel().getRoot();
	if (root.getChildCount() >= 0) {
	    for (Enumeration e = root.children(); e.hasMoreElements();) {
		loadNode((AttributeTreeNode) e.nextElement());
	    }
	}
    }

    private void loadNode(AttributeTreeNode node) {
	attributeList.add(node.getAttribute());
	if (node.getChildCount() >= 0) {
	    for (Enumeration e = node.children(); e.hasMoreElements();) {
		AttributeTreeNode n = (AttributeTreeNode) e.nextElement();
		loadNode(n);
	    }
	}
    }

    @Override
    public void setAttributes(List<Attribute> attributes) {
	this.attributeList = attributes;
	generateAttributeTree(this.attributeList, (DefaultMutableTreeNode) attributeModel.getRoot());
    }

    private void generateAttributeTree(Iterable<Attribute> attributes, DefaultMutableTreeNode node) {
	for (Attribute attribute : attributes) {
		DefaultMutableTreeNode newNode = new AttributeTreeNode(attribute);
		node.add(newNode);
	}
    }

}
